package `in`.srain.cube.util.general

import `in`.srain.cube.concurrent.AppThreads
import `in`.srain.cube.util.internal.AppCallback
import `in`.srain.cube.util.internal.AppConsumer
import `in`.srain.cube.util.internal.AppSupplier
import java.util.concurrent.Callable

object GeneralUtil {

    fun <T> runFromBackgroundToMain(callable: Callable<T>, callback: AppCallback<T>?) {
        AppThreads.runOnIOThread {
            try {
                val t = callable.call()
                callback?.let {
                    AppThreads.runOnMainThread { it.onSuccess(t) }
                }
            } catch (e: Throwable) {
                callback?.let {
                    AppThreads.runOnMainThread { it.onError(e) }
                }
            }
        }
    }

    fun runFromBackgroundToMain(ioRunnable: Runnable, runnable: Runnable?) {
        AppThreads.runOnIOThread {
            ioRunnable.run()

            runnable?.let {
                AppThreads.runOnMainThread(it)
            }
        }
    }

    fun runFromBackgroundToMain(function: () -> Unit, runnable: Runnable? = null) {
        AppThreads.runOnIOThread {
            function.invoke()
            runnable?.let {
                AppThreads.runOnMainThread(it)
            }
        }
    }

    @JvmStatic
    fun <T> runFromBackgroundToMain(supplier: AppSupplier<T>, consumer: AppConsumer<T>) {
        AppThreads.runOnIOThread {
            val t: T = supplier.get()
            AppThreads.runOnMainThread { consumer.accept(t) }
        }
    }

    fun <T> safeGet(supplier: AppSupplier<T>): T? {
        return safeGet(supplier, null)
    }

    fun <T> safeGet(supplier: AppSupplier<T>, fallback: T?): T? {
        return try {
            supplier.get()
        } catch (e: Throwable) {
            fallback
        }
    }
}